package bsh;

import java.util.Map;

import org.objectweb.asm.MethodVisitor;

import bsh.exception.CompilationFailedException;
import bsh.meta.Scope;
import bsh.meta.TypeWrapper;
import bsh.meta.UnfinishedInnerType;

/**
 * Interface interna. Nao deve ser usado de fora do pacote
 * 
 * @author takeshi
 */
public interface CompilerManagerInternals {

    /**
     * @return {@link ReflectionUtils}
     */
    ReflectionUtils reflectionUtils();

    /**
     * @param node node
     * @param unit unit
     * @return {@link NodeCompiler}
     * @throws CompilationFailedException e
     */
    NodeCompiler getNodeCompiler(SimpleNode node, CompilationUnit unit) throws CompilationFailedException;

    /**
     * Faz a coercao do topo do stack para o tipo desejado. Equivalente a
     * {@link #coerceToType(MethodVisitor, TypeWrapper, TypeWrapper, CompilationState)}
     * 
     * @param host {@link MethodVisitor}
     * @param typeWrapper {@link TypeWrapper}
     * @param state {@link CompilationState}
     * @throws CompilationFailedException e
     */
    void coerceStackTopTo(MethodVisitor host, TypeWrapper typeWrapper, CompilationState state) throws CompilationFailedException;

    /**
     * @param host {@link MethodVisitor}
     * @param fromType {@link TypeWrapper}
     * @param typeWrapper {@link TypeWrapper}
     * @param state {@link CompilationState}
     * @throws CompilationFailedException e
     */
    void coerceToType(MethodVisitor host, TypeWrapper fromType, TypeWrapper typeWrapper, CompilationState state)
            throws CompilationFailedException;

    /**
     * Faz a coercao
     * 
     * @param host {@link MethodVisitor}
     * @param fromType {@link TypeWrapper}
     * @param typeWrapper {@link TypeWrapper}
     * @param state {@link CompilationState}
     * @param maxDepth int
     * @throws CompilationFailedException e
     */
    void coerceToType(MethodVisitor host, TypeWrapper fromType, TypeWrapper typeWrapper, CompilationState state, int maxDepth)
            throws CompilationFailedException;

    /**
     * Compila um script
     * 
     * @param script o script
     * @param fields os campos
     * @param scriptName o nome do script
     * @return {@link Class}
     * @throws ParseException e
     * @throws CompilationFailedException e
     */
    Class<? extends Prototype> compile(String script, Map<String, Object> fields, String scriptName) throws ParseException,
            CompilationFailedException;

    /**
     * @param type class
     * @param host host
     * @param state state
     */
    void unbox(Class<?> type, MethodVisitor host, CompilationState state);

    /**
     * Compila
     * 
     * @param script o texto do script
     * @param scriptName o nome da classe gerada
     * @param sourceCode o nome do source
     * @param fields os campos
     * @return Class
     * @throws ParseException e
     * @throws CompilationFailedException e
     */
    Class<? extends Prototype> compile(String script, Map<String, Object> fields, String scriptName, String sourceCode)
            throws ParseException, CompilationFailedException;

    /**
     * Compila
     * 
     * @param script o texto do script
     * @param scriptName o nome da classe gerada
     * @param sourceCode o nome do source
     * @param fields map
     * @param extractor extractor
     * @return Class
     * @throws ParseException e
     * @throws CompilationFailedException e
     */
    Class<? extends Prototype> compile(String script, Map<String, Object> fields, String scriptName, String sourceCode,
            TypeExtractor extractor) throws ParseException, CompilationFailedException;

    /**
     * Compila
     * 
     * @param <E> o tipo da superclasse
     * @param script o texto do script
     * @param scriptName o nome da classe gerada
     * @param sourceCode o nome do source
     * @param fieldTypes os campos
     * @param superType o supertipo
     * @return Class
     * @throws ParseException e
     * @throws CompilationFailedException e
     */
    <E extends Prototype> Class<? extends E> compile(String script, String scriptName, String sourceCode, Map<String, Class<?>> fieldTypes,
            Class<E> superType) throws ParseException, CompilationFailedException;

    /**
     * Compiles an inner class definition and returns the {@link UnfinishedInnerType}. The class is added to the given
     * {@link CompilationUnit} by calling {@link CompilationUnit#addInnerClassDefinition(byte[], UnfinishedInnerType)}. If the class is not
     * annonymous, its name is also added in the given scope as a type alias
     * 
     * @param clName the inner class name
     * @param simpleName the simple name. May be null for annonymous inner class
     * @param unit the declaring compilation unit
     * @param classBlock the body of the class
     * @param scope the declaring scope
     * @param superType the supertype
     * @param interfaces the implemented interfaces
     * @param modifiers the class modifiers
     * @return {@link UnfinishedInnerType}
     * @throws CompilationFailedException e
     */
    UnfinishedInnerType compileInnerClass(String clName, String simpleName, CompilationUnit unit, BSHBlock classBlock, Scope scope,
            TypeWrapper superType, TypeWrapper[] interfaces, int modifiers) throws CompilationFailedException;
}
